package com.views
{
	import com.data.ActivityDAO;
	import com.events.ConnectEvent;
	import com.events.EditActivityEvent;
	import com.events.GraphEditEvent;
	import com.models.WorkFlow;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	
	import mx.controls.Label;
	import mx.core.DragSource;
	import mx.core.UIComponent;
	import mx.effects.Tween;
	import mx.events.TweenEvent;
	import mx.effects.easing.Bounce;
	import mx.events.DragEvent;
	import mx.managers.DragManager;
	import mx.core.Application;
	import mx.effects.Zoom;
	

	/**
	 * Klasse zur Darstellung einer Aktivität im Graphen
	 */
	public class Activity extends UIComponent implements IGraphElement
	{
		
		private var _currentIcon:DisplayObject;
		private var _displayTaskLabel:Label;
		private var _labelChanged:Boolean = false;
		private var _label:String;
		private var _model:WorkFlow;
		private var _background:Sprite;
		private var _selectionBorder:Sprite;
		private var _bgrdChanged:Boolean = false;
		private var _padding:int = 5;
		private var _connect:Boolean = false;
		private var _dataId:String;
		private var _selected:Boolean = false;
		private var _bgrdSprite:Sprite;
		private var _delBorder:Sprite;
		private var _toolTipText:String = "";
		
		/**
		 * Konstruktor
		 * @param model Referenz auf das Model
		 * 
		 */
		public function Activity(model:WorkFlow, data:ActivityDAO)
		{	
			_model = model;
			_dataId = data.dataId;
			toolTip = data.dataId;
			_model.setView(this);
		}
		
		/**
		 * Hinzufügen der grundlegenden Elemente dieser Klasse.
		 * Wird genau einmal aufgerufen, dies findet während der
		 * Instanzierung statt.
		 */
		override protected function createChildren():void
		{
			super.createChildren();
			
			if(_displayTaskLabel == null)
			{
				_displayTaskLabel = new Label();
			}
			
			
			_background = drawRect(100,50);
			addChild(_background);
			addChild(_displayTaskLabel);
			
			
			addListeners();
			
			this.label = "Aktivität";
		}
		
		/**
		 * Aktualisierung der Eigenschaften der Elemente dieser Klasse.
		 * Wird auch bei der Instanzierung aufgerufen.
		 */
		override protected function commitProperties():void
		{
			super.commitProperties();
			
			if(_labelChanged) 
			{
				_labelChanged = false;
				_displayTaskLabel.text = _label;
				_bgrdChanged = true;
			}
		}
		
		/**
		 * Text der Aktivität
		 * @param value
		 * 
		 */
		public function set label(value:String):void
		{
			_label = value;
			_labelChanged = true;
			
			invalidateProperties();
			invalidateDisplayList();
			
		}
		
		/**
		 * Eindeutige Indentifizierer
		 * @return 
		 * 
		 */
		public function get dataId():String
		{
			return _dataId;
		}
		
		public function get background():Sprite
		{
			return _background;
		}
		
		
		/**
		 * Hinzufügen der EventListener
		 */
		protected function addListeners():void
		{
			addEventListener(EditActivityEvent.EDIT, editHandler);
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
			addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
			addEventListener(DragEvent.DRAG_EXIT, dragExitHandler);
			addEventListener(DragEvent.DRAG_OVER, dragOverHandler);
			addEventListener(DragEvent.DRAG_COMPLETE, dragCompleteHandler);
			addEventListener(MouseEvent.CLICK, mouseClickHandler);
			addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
			addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
			_model.addEventListener(ConnectEvent.UPDATE, connectUpdateHandler);
			_model.addEventListener(GraphEditEvent.UPDATE, graphEditUpdateHandler);
			
		}
		/**
		 * Entfernen der EventListener
		 */
		protected function removeListeners():void
		{
			removeEventListener(EditActivityEvent.EDIT, editHandler);
			removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
		}
		
		/**
		 * Behandlung der EditActivityEvents
		 * @param evt EditActivityEvent
		 * 
		 */
		protected function editHandler(evt:EditActivityEvent):void
		{
			
		}
		
		/**
		 * Zeichnet ein Rechteck
		 * @param width Breite des Rechtecks
		 * @param height Höhe des Rechtecks
		 * @return Rückgabe des Rechtecks als Sprite
		 * 
		 */
		protected function drawRect(width:int, height:int):Sprite
		{
			var thickness:int = 2;
			var lineColor:uint = 0x0055FF;
			var selectedColor:uint = 0xCC0000;
			
			
			var sprite:Sprite = new Sprite();
			sprite.graphics.lineStyle(thickness, lineColor, 1);
			sprite.graphics.beginFill(0x0055FF, 0.5);
			var corner:int = height < width ? height / 4 : width / 4;
			sprite.graphics.drawRoundRect(0, 0, width, height, corner, corner);
			sprite.graphics.endFill();
			if(_selected)
			{
				_selectionBorder = new Sprite();
				_selectionBorder.graphics.lineStyle(thickness, selectedColor, 1);
				var side:int = height < width ? width/4 : height/4;
				_selectionBorder.graphics.drawRoundRect(0, 0, width+10, height+10, side, side);
				_selectionBorder.x = -5;
				_selectionBorder.y = -5;
				_selectionBorder.alpha = 0.5;
				addChild(_selectionBorder);
			}
			
			return sprite;
		}
		
		/**
		 * @private
		 * @param unscaledWidth
		 * @param unscaledHeight
		 * 
		 */
		override protected function updateDisplayList(
			unscaledWidth:Number, 
			unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if(_bgrdChanged)
			{
				_bgrdChanged = false;
				removeChild(_background);
				if(_selectionBorder)
				{
					removeChild(_selectionBorder);
					_selectionBorder = null;
				}
					
				_background = drawRect(
					_displayTaskLabel.textWidth + _padding,
					_displayTaskLabel.textHeight + _padding);
				_displayTaskLabel.width = _displayTaskLabel.textWidth + 5;
				_displayTaskLabel.height = _displayTaskLabel.textHeight + 5;
				
				if(!_selected)
				{
					width = _background.getBounds(this).width;
					height = _background.getBounds(this).height;
				}
				addChild(_background);
			}
			
		}
		
		/**
		 * Behandlung des MouseDown Events
		 * @param evt
		 * 
		 */
		public function mouseDownHandler(evt:MouseEvent):void
		{
			if(evt.shiftKey)
			{
				_model.removeActivity(_dataId);
			}
			else
			{
				var dragSource:DragSource = new DragSource();
				dragSource.addData(this, "activity");
				var dragInitiator:UIComponent = evt.currentTarget as UIComponent;
				var offsetX:int = dragInitiator.mouseX;
				var offsetY:int = dragInitiator.mouseY;
				dragSource.addData(offsetX, 'offsetX');
				dragSource.addData(offsetY, 'offsetY');
				var proxy:UIComponent = new ActivityProxy(
					_displayTaskLabel.width,
					_displayTaskLabel.height);
				_model.proxy = proxy as UIComponent;
				proxy.alpha = .5;
				dragSource.addData(proxy, "proxy");
				DragManager.doDrag(this, dragSource, evt, proxy);
				_model.setSelectedElement(this);
			}
		}
		
		/**
		 * Behandlung des DragEnter Events
		 * @param evt
		 * 
		 */
		protected function dragEnterHandler(evt:DragEvent):void
		{
			if(evt.dragSource.hasFormat("decision"))
			{
				var target:Activity = Activity(evt.currentTarget);
				DragManager.acceptDragDrop(target);
				var initiatorDec:Decision = Decision(evt.dragInitiator);
				initiatorDec.connect = true;
				initiatorDec.visible = true;
			}
			else if(evt.dragSource.hasFormat("activity"))
			{
				var initiatorAct:Activity = Activity(evt.dragInitiator);
				if(initiatorAct.dataId != dataId)
				{
					target = Activity(evt.currentTarget);
					DragManager.acceptDragDrop(target);
					initiatorAct.connect = true;
					initiatorAct.visible = true;
				}
			}
		}
		
		/**
		 * Behandlung des DragDrop Events
		 * @param evt
		 * 
		 */
		protected function dragDropHandler(evt:DragEvent):void
		{
			if(evt.dragSource.hasFormat("decision"))
			{
				var initiator:Decision = Decision(evt.dragInitiator);
				var target:IGraphElement = IGraphElement(evt.currentTarget);
				initiator.connect = false;
				initiator.visible = true;
				_model.addConnection(initiator, target);
			}
			else if(evt.dragSource.hasFormat("activity"))
			{
				var initiatorAct:Activity = Activity(evt.dragInitiator);
				target = IGraphElement(evt.currentTarget);
				initiatorAct.connect = false;
				initiatorAct.visible = true;
				_model.addConnection(initiatorAct, target);
			}
		}
		
		/**
		 * Behandlung des DragExit Events
		 * @param evt
		 * 
		 */
		protected function dragExitHandler(evt:DragEvent):void
		{	
			if(evt.dragSource.hasFormat("decision"))
			{
				var initiator:Decision = Decision(evt.dragInitiator);
				
				initiator.visible = false;
				initiator.connect = false;	
				
			}
			if(evt.dragSource.hasFormat("activity"))
			{
				var initiatorAct:Activity = Activity(evt.dragInitiator);
				
				initiatorAct.visible = false;
				initiatorAct.connect = false;	
				
			}
		}
		
		private function dragCompleteHandler(evt:DragEvent):void
		{
			
		}
		
		/**
		 * Behandlung des ConnectUpdate Events
		 * @param evt
		 * 
		 */
		protected function connectUpdateHandler(evt:ConnectEvent):void
		{
			
		}
		
		private function graphEditUpdateHandler(evt:GraphEditEvent):void
		{
			if(_dataId == evt.data.dataId)
				label = evt.data.text;
		}
		
		
		/**
		 * Behandlung des DragOver Events
		 * @param evt
		 * 
		 */
		protected function dragOverHandler(evt:DragEvent):void
		{
			
		}
		
		private function mouseClickHandler(evt:MouseEvent):void
		{
			if(evt.shiftKey)
			{
				_model.removeActivity(_dataId);
			}
			else
				_model.setSelectedElement(this);
		}
		
		private function doubleClickHandler(evt:MouseEvent):void
		{
			_model.removeActivity(_dataId);
		}
		
		/**
		 * Status zur Bestimmung des Aktionszustandes.
		 * Wenn die gerade ausgeführte Aktion zu der Erzeugung 
		 * einer neuen Verbindung führt ist dieser Wert true.
		 * @return 
		 * 
		 */
		public function get connect():Boolean
		{
			return _connect;
		}
		public function set connect(value:Boolean):void
		{
			_connect = value;
			trace("Activity is connecting");
		}
		
		/**
		 * Bestimmt ob das Aktivität ausgewählt ist
		 * @return 
		 * 
		 */
		public function get selected():Boolean
		{
			return _selected;
		}
		public function set selected(value:Boolean):void
		{
			_selected = value;
			_bgrdChanged = true;
			invalidateDisplayList();
		}
		
		public function onTweenUpdate(val:int):void
	    {
	    	if(_delBorder)
	    	{
		    	_delBorder.width = val;
		    	_delBorder.height = val;
	    	}
	    }
	    public function onTweenEnd(val:int):void
	    {
	    	
	    }
	    
	    public function rollOverHandler(evt:MouseEvent):void
	    {
	    	if(_model.tool == "delete")
	    	{
		    	var thickness:int = 2;
				var lineColor:uint = 0x0055FF;
				var selectedColor:uint = 0xCC0000;
		    	
		    	_delBorder = new Sprite();
				_delBorder.graphics.lineStyle(thickness, selectedColor, 1);
				var side:int = height < width ? width : height;
				_delBorder.graphics.drawCircle(width/2, height/2, side/2 + 10);
				_delBorder.x = 0;
				_delBorder.y = 0;
				_delBorder.alpha = 0.5;
				/* 
				_zoom = new Zoom(_delBorder as UIComponent);
				_zoom.easingFunction = mx.effects.easing.Bounce.easeOut;
				_zoom.duration = 500;
				_zoom.zoomHeightFrom = _zoom.zoomWidthFrom = 2;
				_zoom.zoomHeightTo = _zoom.zoomWidthTo = 1;
				 */
				var tween:Tween = new Tween(this, side + 60, 2*(side/2+10), 500);
		    	tween.easingFunction = mx.effects.easing.Bounce.easeOut;
				addChild(_delBorder);
				//_zoom.play();
	    	}
	    }
	    
	    public function rollOutHandler(evt:MouseEvent):void
	    {
	    	if(_delBorder)
	    	{
	    		removeChild(_delBorder);
	    		_delBorder = null;
	    	}
	    }
		
		
		
	}
}